import { Meta, Story } from '@storybook/addon-docs/blocks';

<Meta title="Docs/Helpers/Selection" />

# Selection

---

Out of the box, reaflow supports selection handled either manually or
semi-automatic with hotkeys using a hook and [reakeys](https://github.com/reaviz/reakeys).

## Selection Hook
The `useSelection` hooks will automatically manage selection state and hotkeys
for you. To set it up, simply import the `useSelection` hook and pass the hook
the `nodes`, `edges` and any default selections you like.

The hook accepts the following:

```ts
export interface SelectionProps {
  /**
   * Current selections.
   */
  selections?: string[];

  /**
   * Node datas.
   */
  nodes?: NodeData[];

  /**
   * Edge datas.
   */
  edges?: EdgeData[];

  /**
   * Hotkey types.
   */
  hotkeys?: HotkeyTypes[];

  /**
   * Disabled or not.
   */
  disabled?: boolean;

  /**
   * On selection change.
   */
  onSelection?: (value: string[]) => void;

  /**
   * On data change.
   */
  onDataChange?: (nodes: NodeData[], edges: EdgeData[]) => void;
}
```

and returns the following:

```ts
export interface SelectionResult {
  /**
   * Selections id array.
   */
  selections: string[];

  /**
   * Clear selections method.
   */
  clearSelections: (value?: string[]) => void;

  /**
   * A selection method.
   */
  addSelection: (value: string) => void;

  /**
   * Remove selection method.
   */
  removeSelection: (value: string) => void;

  /**
   * Toggle existing selection on/off method.
   */
  toggleSelection: (value: string) => void;

  /**
   * Set internal selections.
   */
  setSelections: (value: string[]) => void;

  /**
   * On click event pass through.
   */
  onClick?: (
    event: React.MouseEvent<SVGGElement, MouseEvent>,
    data: any
  ) => void;

  /**
   * On canvas click event pass through.
   */
  onCanvasClick?: (event?: React.MouseEvent<SVGGElement, MouseEvent>) => void;

  /**
   * On keydown event pass through.
   */
  onKeyDown?: (event: React.KeyboardEvent<SVGGElement>) => void;
}
```

The hotkeys that are bound via this hook are:

- `ctrl/meta + a`: Select all nodes
- `escape`: Defoucs selections
- `ctrl/meta + click`: Toggle node selection
- `backspace`: Remove selected nodes

Below is a typical setup of where you define the selection hook.

```ts
import { NodeData, EdgeData, useSelection } from 'reaflow';

const [nodes, setNodes] = useState<NodeData[]>([
  {
    id: '1',
    text: 'Node 1'
  },
  {
    id: '2',
    text: 'Node 2'
  }
]);

const [edges, setEdges] = useState<EdgeData[]>([
  {
    id: '1-2',
    from: '1',
    to: '2'
  }
]);

const { selections, onCanvasClick, onClick, onKeyDown, clearSelections } = useSelection({
  nodes,
  edges,
  onDataChange: (n, e) => {
    console.info('Data changed', n, e);
    setNodes(n);
    setEdges(e);
  },
  onSelection: (s) => {
    console.info('Selection', s);
  }
});
```

Once defined you can pass these onto the canvas like:

```jsx
<Canvas
  nodes={nodes}
  edges={edges}
  selections={selections}
  node={
    <Node
      onClick={onClick}
      onKeyDown={onKeyDown}
      onRemove={(event, node) => {
        const result = removeAndUpsertNodes(nodes, edges, node);
        setEdges(result.edges);
        setNodes(result.nodes);
        clearSelections();
      }}
    />
  }
  edge={
    <Edge
      onClick={onClick}
    />
  }
  onCanvasClick={onCanvasClick}
/>
```

and the hook will handle setting the rest up for you. In the `onSelection`
block you can define custom rules for selection as well.

## Manual Selection Management
If you don't wish to use the `useSelection` hook you can handle the selections
yourself manually. This is as simple as defining a state for the selections
and just passing it on.

```jsx
import { NodeData, EdgeData } from 'reaflow';

const [selections, setSelections] = useState<string[]>([]);

const [nodes] = useState<NodeData[]>([
  {
    id: '1',
    text: 'Node 1'
  },
  {
    id: '2',
    text: 'Node 2'
  }
]);

const [edges] = useState<EdgeData[]>([
  {
    id: '1-2',
    from: '1',
    to: '2'
  }
]);
```

then similar to how we passed the selections with the hook, we do the same
thing with the manual selection state.

```jsx
<Canvas
  nodes={nodes}
  edges={edges}
  selections={selections}
  node={
    <Node
      onClick={(event, node) => {
        console.log('Selecting Node', event, node);
        setSelections([node.id]);
      }}
    />
  }
  edge={
    <Edge
      onClick={(event, edge) => {
        console.log('Selecting Edge', event, edge);
        setSelections([edge.id]);
      }}
    />
  }
  onCanvasClick={(event) => {
    console.log('Canvas Clicked', event);
    setSelections([]);
  }}
  onLayoutChange={layout => console.log('Layout', layout)}
/>
```
